﻿using Futajma.MigrationStudio.DataDefinition;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace Futajma.MigrationStudio.GenericPersistance
{
    [ObfuscationAttribute(Exclude = true, ApplyToMembers = true)]
    public enum State
    {
        True = 1,
        False = 0,
        Issue = 2
    }

    [ObfuscationAttribute(Exclude = true, ApplyToMembers = true)]
    public class Action
    {
        public string NodeName { get; set; }
        public string NodePath { get; set; }
        public string NodeSourceId { get; set; }
        public string SourceNodePath { get; set; }
        public SharePointType Type { get; set; }
        public bool Exclude { get; set; }
        public ActionType ActionType { get; set; }
        public State Completed { get; set; }
        //public Guid InternalNodeId { get; set; }
    }

    [ObfuscationAttribute(Exclude = true, ApplyToMembers = true)]
    public enum ActionType
    {
        Undefined = 0,
        Move = 1,
        Exclude = 2,
        Insert = 3,
        Remove = 4,
        Rename = 5,
        TemplateChange = 6,
        Convert = 7,
        InsertFromSource = 8
    }

    public delegate void ExportHandlerInformationUpdate(int actionItems);

    public class ActionItemHandler
    {
        #region Membervariables
        List<Action> _actionList = new List<Action>();
        #endregion

        #region Propoerties
        public List<Action> ActionList { get { return _actionList; } }
        #endregion

        #region Events

        public ExportHandlerInformationUpdate ExportHandlerInformationUpdate;

        #endregion

        #region Action Methods
        public virtual void MoveAction(TreeNode source, TreeNode target)
        {
            DataNode data = source.Tag as DataNode;

            var action = new Action() { ActionType = ActionType.Move, Type = data.SharePointType, NodeSourceId = data.SourceId, NodeName = data.Title, SourceNodePath = GetPathToRoot(source), NodePath = GetPathToRoot(target) };
            ActionList.Add(action);
            Console.WriteLine(string.Format("Drop Source from [{0}] to [{1}]", GetPathToRoot(source), GetPathToRoot(target)));
            SendHandlerInformation();
        }
        public virtual void InsertFromSourceAction(TreeNode source, TreeNode target)
        {
            DataNode data = source.Tag as DataNode;

            var action = new Action() {ActionType = ActionType.InsertFromSource, Type = data.SharePointType, NodeSourceId = data.SourceId, NodeName = data.Title, SourceNodePath = GetPathToRoot(source), NodePath = GetPathToRoot(target) };
            ActionList.Add(action);
            Console.WriteLine(string.Format("Drop Source from [{0}] to [{1}]", GetPathToRoot(source), GetPathToRoot(target)));
            SendHandlerInformation();
        }

        public virtual void ExcludeAction(TreeNode node, bool exclude)
        {
            DataNode data = node.Tag as DataNode;

            var action = new Action() { ActionType = ActionType.Exclude, Type = data.SharePointType, NodeSourceId = data.SourceId, NodeName = data.Title, NodePath = GetPathToRoot(node), Exclude = exclude };
            ActionList.Add(action);
            Console.WriteLine(string.Format("Exclude node [{0}] is {1}", GetPathToRoot(node), exclude));
            SendHandlerInformation();
        }

        public virtual void InsertAction(TreeNode node)
        {
            DataNode data = node.Tag as DataNode;

            var action = new Action() { ActionType = ActionType.Insert, Type = data.SharePointType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
            ActionList.Add(action);

            Console.WriteLine(string.Format("New Node inserted [{0}]", GetPathToRoot(node)));
            SendHandlerInformation();
        }

        public virtual void RemoveAction(TreeNode node, bool singleNode)
        {
            DataNode data = node.Tag as DataNode;

            //var action = new Action() { InternalNodeId = data.Id, ActionType = ActionType.Remove, Type = data.SharePointType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
            
            // check if item was direct inserted or not

            //var subList = _actionList.Where(e => e.InternalNodeId == data.Id && (e.ActionType == ActionType.InsertFromSource || e.ActionType == ActionType.Insert)).ToList();
            
            //if (subList.Count == 1)
            //{
            //    // direct insert, remove all actions
            //    _actionList.RemoveAll(e => e.InternalNodeId == data.Id);
            //}
            //else
            //{
            //    // indirect insert, remove all actions except the first move and change action

            //    var list2 = _actionList.Where(e => e.InternalNodeId == data.Id).ToList();

            //    if (list2.Count > 0)
            //    {
            //        list2[0].ActionType = ActionType.Remove;

            //        for (int i = 1; i < list2.Count;i++ )
            //        {
            //            _actionList.Remove(list2[i]);
            //        }
            //    }
                //else if (singleNode)
                //{
                    var action = new Action() {ActionType = ActionType.Remove, Type = data.SharePointType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
                    ActionList.Add(action);
                //}
            //}
            
            Console.WriteLine(string.Format("Node removed [{0}]", GetPathToRoot(node)));
            
            SendHandlerInformation();
            
        }

        public virtual void RenameAction(TreeNode node, string newName)
        {
            DataNode data = node.Tag as DataNode;

            var action = new Action() { ActionType = ActionType.Rename, Type = data.SharePointType, NodeName = newName, NodePath = GetPathToRoot(node) };
            ActionList.Add(action);
            Console.WriteLine(string.Format("Node renamed [{0}] to [{1}]", GetPathToRoot(node), newName));
            SendHandlerInformation();
        }

        public virtual void DisableFolderStructureAction(TreeNode node, bool remove)
        {
            DataNode data = node.Tag as DataNode;

            var action = new Action() { ActionType = ActionType.Rename, Type = data.SharePointType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
            ActionList.Add(action);
            Console.WriteLine(string.Format("{0} folder structure [{1}] to [{2}]", remove ? "Remove" : "Enable", GetPathToRoot(node), data.Title));
            SendHandlerInformation();
        }

        //public virtual void TemplateChangeAction(TreeNode node)
        //{
        //    DataNode data = node.Tag as DataNode;

        //    var action = new Action() { ActionType = ActionType.TemplateChange, Type = data.SharePointType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
        //    ActionList.Add(action);cfd
        //    Console.WriteLine(string.Format("Node template changed [{0}], template [{1}]", GetPathToRoot(node), "Template xy"));
        //    SendHandlerInformation();
        //}

        public virtual void ConvertNode(TreeNode node, SharePointType newType)
        {
            DataNode data = node.Tag as DataNode;

            var action = new Action() {ActionType = ActionType.Convert, Type = newType, NodeName = data.Title, NodePath = GetPathToRoot(node) };
            ActionList.Add(action);

            Console.WriteLine(string.Format("Convert Node [{0}] to [{1}]", GetPathToRoot(node), newType.ToString("G")));
            SendHandlerInformation();
        }
        #endregion

        #region Private Methods
        string GetPathToRoot(TreeNode node)
        {
            string path = "";
            var runner = node;
            while (runner != null)
            {
                path = string.Format("{0}/{1}", runner.Text, path);
                runner = runner.Parent;
            }
            return path;
        }

        public void SendHandlerInformation()
        {
            if (ExportHandlerInformationUpdate != null)
            {
                ExportHandlerInformationUpdate(_actionList.Count);
            }
        }

        #endregion

        #region Load/Save Methods
        public virtual void LoadXml(Stream stream)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Action>));
            var other = (List<Action>)(serializer.Deserialize(stream));
            _actionList.Clear();
            _actionList.AddRange(other);
        }

        public virtual StringBuilder Save()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = new UnicodeEncoding(false, false);
            settings.Indent = true;
            settings.OmitXmlDeclaration = true;

            var serializer = new XmlSerializer(typeof(List<Action>));
            StringBuilder sb = new StringBuilder();
            using (XmlWriter writer = XmlWriter.Create(sb, settings))
            {
                serializer.Serialize(writer, _actionList);
            }
            return sb;
        }
        #endregion

        #region ResetActions
        public virtual void ResetActions()
        {
            _actionList.Clear();
        }

        //public virtual void CompressActions()
        //{
        //    var toDelete = new List<Action>();

        //    var removeList = _actionList.Where(e => e.ActionType == ActionType.Remove);

        //    foreach (var action in removeList)
        //    {
        //        var index = _actionList.IndexOf(action);

        //        //Guid id = action.InternalNodeId;

        //        // check if item was inserted

        //        //var subList = _actionList.Where(e => e.InternalNodeId == action.InternalNodeId && _actionList.IndexOf(e) <= index);

        //        // check if item was not direct inserted, only via folder

        //        var subList = _actionList.Where(e => e.InternalNodeId == action.InternalNodeId && _actionList.IndexOf(e) <= index);

        //        toDelete.AddRange(subList);
        //    }
        //    foreach (var delete in toDelete)
        //    {
        //        _actionList.Remove(delete);
        //    }

        //    SendHandlerInformation();
        //}
        #endregion

        #region ExportMethods
        public virtual void SaveAsCsv(string filePath)
        {
            // Consolidate List

            //Dictionary<string, Action> consList = new Dictionary<string, Action>();

            //foreach (var action in _actionList)
            //{
            //    if (consList.ContainsKey(action.SourceNodePath) && action.ActionType == ActionType.Move)
            //    {
            //        consList[action.SourceNodePath] = action;
            //    }
            //    else
            //    {
            //        consList.Add(action.SourceNodePath, action);
            //    }
            //}

            string format = "{0};{1};{2};{3};{4};{5};{6}";
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(string.Format(format, "ActionType", "NodeId", "NodeName", "NodePath", "SourceNodePath", "Type", "Exclude"));

            foreach (var action in _actionList)
            {
                sb.AppendLine(string.Format(format, action.ActionType, action.NodeSourceId, action.NodeName, action.NodePath, action.SourceNodePath, action.Type, action.Exclude));
            }

            File.WriteAllText(filePath, sb.ToString());
        }
        #endregion
    }
}
